package com.hrms.hrms_workflow.util;

import cn.hutool.core.util.StrUtil;
import com.hrms.hrms_workflow.constant.FLOW_KEY;
import com.hrms.hrms_workflow.vo.ApprovalDetailDTO;
import com.hrms.hrms_workflow.vo.HistoryTaskVO;
import com.hrms.hrms_workflow.vo.TaskVO;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;

import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
public class WorkFlowUtil {

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    /**
     * 创建流程实例
     * @param xml
     * @param name
     * @return
     */
    public String workLoads(String xml, String name) {
        Deployment deploy = processEngine.getRepositoryService().createDeployment()
                .addClasspathResource(xml) // 部署一个流程 "process/example.bpmn20.xml"
                .name(name) //"流程案例"
                .deploy();
        return deploy.getId();

    }

    public String startflow(String code,Map<String, Object> map ) {
//        String id = "example:1:2e236113-d0d0-11ef-a1ad-005056c00001";
//        String businessKey = "testflow";
//        HashMap<String, Object> map = new HashMap<>();
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(code,map);
        System.out.println(processInstance.toString());
        return processInstance.getProcessInstanceId();
    }

    /**
     * 找到用户待处理的流程实例
     *
     * @return
     */
    public List<TaskVO> findCurrentFlowByAssignee(String name) {
        List<Task> currentTasks = taskService.createTaskQuery()
                .taskAssignee(name) //"zhangzhao"
                .list();
//        String processInstanceId = list.get(0).getProcessInstanceId();
        List<TaskVO> taskVOs = new ArrayList<>();
        for (Task task : currentTasks) {
            TaskVO taskVO = new TaskVO();
            taskVO.setId(task.getId());
            taskVO.setName(task.getName());
            taskVO.setAssignee(task.getAssignee());
            taskVO.setProcessDefinitionId(task.getProcessDefinitionId());
            taskVO.setInsId(task.getProcessInstanceId());
            // 获取流程变量
            Map<String, Object> variables = runtimeService.getVariables(task.getExecutionId());
            taskVO.setVariables(variables);

            taskVOs.add(taskVO);
        }
        return taskVOs;
    }

    /**
     * 获取所有流程实例
     *
     * @return
     */

    /**
     * 获取当前运行中的任务
     *
     * @return
     */
    public List<TaskVO> findCurrentFlowByProcessInsId(String processInstanceId) {
        List<Task> currentTasks = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .list();
        // 当前任务信息
//        currentTasks.forEach(task -> {
//            String taskName = task.getName();        // 节点名称
//            String assignee = task.getAssignee();    // 当前处理人
//            String taskId = task.getId();            // 任务ID
//        });
        List<TaskVO> taskVOs = new ArrayList<>();
        for (Task task : currentTasks) {
            TaskVO taskVO = new TaskVO();
            taskVO.setId(task.getId());
            taskVO.setName(task.getName());
            taskVO.setAssignee(task.getAssignee());
            taskVO.setProcessDefinitionId(task.getProcessDefinitionId());
            taskVO.setInsId(task.getProcessInstanceId());


            // 获取流程变量
            Map<String, Object> variables = runtimeService.getVariables(task.getExecutionId());
            taskVO.setVariables(variables);

            taskVOs.add(taskVO);
        }
        return taskVOs;
    }
    /**
     * 完成流程节点
     */
    public void completeflow(String id,Map<String, Object> map) {
//        String id = "example:1:2e236113-d0d0-11ef-a1ad-005056c00001";
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("assign","zhangzhao");
//        List<TaskVO> taskVOS = this.findCurrentFlowByProcessInsId(id);
        Object comment = map.get("approvalComment");
        map.remove("approvalComment");
        map.put("approvalComment_"+ id,comment);
        taskService.setVariablesLocal(id,map);
        taskService.complete(id);
    }

    /**
     * 驳回流程
     * @param processInsId
     * @param variables
     */
    public void reject(String processInsId, Map<String, Object> variables) {
        // 验证流程实例是否存在
        ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInsId)
                .singleResult();
        if (instance == null) {
            throw new FlowableObjectNotFoundException("流程实例不存在或已结束");
        }
        // 终止流程实例（自动删除未完成任务）
        runtimeService.deleteProcessInstance(
                processInsId,
                "REJECTED: " + variables.get("reject")
        );
    }


    // 根据流程实例ID查询流程实例
    public ProcessInstance processInstance(String processInstanceId) {
        // 根据流程实例ID查询流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        return processInstance;
    }

    /**
     * 查询历史审批记录
     *
     * @return
     */
    public List<HistoryTaskVO> finfHistory(String processInstanceId) {
        List<HistoricTaskInstance> historicTasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByTaskCreateTime().asc()
                .list();

        if (historicTasks == null) {
            return new ArrayList<>();
        }
        List<HistoryTaskVO> historyList = new ArrayList<>();
        for (HistoricTaskInstance task : historicTasks) {
            HistoryTaskVO taskVO = new HistoryTaskVO();
            BeanUtils.copyProperties(task,taskVO);
            // 获取审批意见（假设审批意见存储在名为 "approvalComment" 的变量中）
            List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery()
                    .taskId(task.getId())
                    .variableName("approvalComment_"+task.getId())
                    .list();

            String approvalComment = variables.isEmpty() ? null : (String) variables.get(0).getValue();
            taskVO.setApprovalComment(approvalComment);
            historyList.add(taskVO);
        }
        return historyList;
    }

    /**
     * 获取流程实例中特定流程变量
     * @param
     * @return
     */
    public String getVariablesDetail(String processInstanceId,String key) {
        Map<String, Object> variables = runtimeService.getVariables(processInstanceId);
        String businessData = (String) variables.get(key); //"formData"
        return businessData;
    }

    /**
     * 获取流程实例详细信息
     * @param processInstanceId
     * @return
     */
    public ApprovalDetailDTO approvalDetail(String processInstanceId) {
        ApprovalDetailDTO dto = new ApprovalDetailDTO();
        ProcessInstance processInstance = this.processInstance(processInstanceId);
        boolean isEnded = processInstance == null;
        dto.setProcessStatus(isEnded ? "已结束" : "运行中");

        // 2. 获取流程定义信息
        if (!isEnded) {
            dto.setProcessDefinitionName(processInstance.getProcessDefinitionName());
            dto.setStartUserId(getVariablesDetail(processInstanceId,"initiator"));
            dto.setProcessInstanceId(processInstance.getProcessInstanceId());
            dto.setStartTime(processInstance.getStartTime());
            // taskVo
            List<TaskVO> taskVOS = this.findCurrentFlowByProcessInsId(processInstanceId);
            dto.setCurrentTasks(taskVOS);
            // 流程变量
            Map<String, Object> variables = runtimeService.getVariables(processInstanceId);

            dto.setVariables(variables);
        }else {
            // 查询历史流程实例
            HistoricProcessInstance historicInstance = historyService
                    .createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .singleResult();

            if (historicInstance == null) {
                throw new FlowableObjectNotFoundException("流程不存在或未结束");
            }
            // 基础信息
            dto.setProcessInstanceId(historicInstance.getId());
            dto.setStartTime(historicInstance.getStartTime());

            // 获取发起
            HistoricVariableInstance initiatorVar = historyService
                    .createHistoricVariableInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .variableName("initiator")
                    .singleResult();
            dto.setStartUserId(initiatorVar != null ? (String) initiatorVar.getValue() : null);
            // 流程定义名称
            ProcessDefinition processDefinition = repositoryService
                    .getProcessDefinition(historicInstance.getProcessDefinitionId());
            dto.setProcessDefinitionName(processDefinition.getName());
            dto.setProcessDefinitionId(historicInstance.getProcessDefinitionId());
            List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .list();
            Map<String , Object> hashmap = new HashMap<>();
            variables.stream().filter(item ->
                item.getTaskId() == null
            ).forEach(item -> {
                hashmap.put(item.getVariableName(), item.getValue());
            });
            dto.setVariables(hashmap);
        }
        //historyVo
        List<HistoryTaskVO> historyTaskVOS = this.finfHistory(processInstanceId);
        dto.setHistoryTasks(historyTaskVOS);

        return dto;
    }

    /**
     * 获取我申请的流程实例
     * @param name
     * @return
     */
    public List<ApprovalDetailDTO> approvalDetailList(String name) {
        List<HistoricProcessInstance> processes = null;
        if (name == null) {
            //校验是否是管理员
            processes = historyService
                    .createHistoricProcessInstanceQuery()
                    .orderByProcessInstanceStartTime().desc()
                    .list();
        }else {
            processes = historyService
                    .createHistoricProcessInstanceQuery()
                    .variableValueEquals("initiator", name)
                    .orderByProcessInstanceStartTime().desc()
                    .list();
        }
        List<ApprovalDetailDTO> dtos = processes.stream()
                .map(instance -> {
                    ApprovalDetailDTO dto = new ApprovalDetailDTO();
                    // 基础流程信息
                    dto.setProcessInstanceId(instance.getId());
                    dto.setStartTime(instance.getStartTime());

                    // 流程定义名称
                    ProcessDefinition processDefinition = repositoryService
                            .getProcessDefinition(instance.getProcessDefinitionId());
                    dto.setProcessDefinitionId(instance.getProcessDefinitionId());
                    dto.setProcessDefinitionName(processDefinition.getName());
                    List<HistoryTaskVO> historyTaskVOS = this.finfHistory(instance.getId());
                    dto.setHistoryTasks(historyTaskVOS);
                    //Variable
                    List<HistoricVariableInstance> variables = historyService.createHistoricVariableInstanceQuery()
                            .processInstanceId(instance.getId())
                            .list();
                    Map<String, Object> hashmap = new HashMap<>();
                    variables.stream().filter(item ->
                            item.getTaskId() == null
                    ).forEach(item -> {
                        hashmap.put(item.getVariableName(), item.getValue());
                    });
                    //被驳回
                    if (instance.getDeleteReason() != null &&
                            instance.getDeleteReason().startsWith("REJECTED:")) {
                        dto.setProcessStatus("被驳回");
                        hashmap.put("reject",instance.getDeleteReason().substring("REJECTED:".length()));
                    }else {
                        dto.setProcessStatus(instance.getEndTime() != null ? "已结束" : "运行中");

                    }
                    // 2. 获取流程定义信息
                    if (dto.getProcessStatus().equals("运行中")) {
                        // taskVo
                        List<TaskVO> taskVOS = this.findCurrentFlowByProcessInsId(instance.getId());
                        dto.setCurrentTasks(taskVOS);
                    }
                    dto.setVariables(hashmap);

                    HistoricVariableInstance initiatorVar = historyService
                            .createHistoricVariableInstanceQuery()
                            .processInstanceId(instance.getId())
                            .variableName("initiator")
                            .singleResult();
                    dto.setStartUserId(initiatorVar != null ? (String) initiatorVar.getValue() : null);
                    return dto;
                })
                .collect(Collectors.toList());
        return dtos;
    }
    /**
     * 根据流程定义ID查询所有流程实例
     */
    public void getProcessInstancesByProcessDefinitionKey(String processDefinitionKey) {
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery()
                .processDefinitionKey(processDefinitionKey)
                .list();
    }

    /**
     * 根据条件查询指定的流程任务
     * @param params
     */
    public List<TaskVO> dynamicQuery(Map<String, Object> params) {
        TaskQuery query = taskService.createTaskQuery();

        if (params.containsKey("taskId")) {
            query.taskId((String) params.get("taskId"));
        }
        if (params.containsKey("taskName")) {
            query.taskName((String) params.get("taskName"));
        }
        if (params.containsKey("processInstanceId")) {
            query.processInstanceId((String) params.get("processInstanceId"));
        }
        if (params.containsKey("dueBefore")) {
            query.taskDueBefore((Date) params.get("dueBefore"));
        }
        if (params.containsKey("createdAfter")) {
            query.taskCreatedAfter((Date) params.get("createdAfter"));
        }
        if (params.containsKey("processDefinitionKey")) {
            query.processDefinitionKey((String) params.get("processDefinitionKey"));
        }
        List<Task> list = query.list();
        List<TaskVO> taskVOs = new ArrayList<>();
        for (Task task : list) {
            TaskVO taskVO = new TaskVO();
            taskVO.setId(task.getId());
            taskVO.setName(task.getName());
            taskVO.setAssignee(task.getAssignee());
            taskVO.setProcessDefinitionId(task.getProcessDefinitionId());
            taskVO.setInsId(task.getProcessInstanceId());
            // 获取流程变量
            Map<String, Object> variables = runtimeService.getVariables(task.getExecutionId());
            taskVO.setVariables(variables);

            taskVOs.add(taskVO);
        }
        return taskVOs;
    }

    /**
     * 根据流程定义ID获取BPMN XML
     *
     * @param processDefinitionId 流程定义ID
     * @return BPMN XML字符串
     */
    public String getProcessDefinitionXml(String processDefinitionId) {
        // 查询指定ID的流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId)
                .singleResult();

        if (processDefinition == null) {
            throw new RuntimeException("未找到对应的流程定义: " + processDefinitionId);
        }

        // 获取BPMN XML
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        BpmnXMLConverter converter = new BpmnXMLConverter();
        return StrUtil.utf8Str(converter.convertToXML(bpmnModel));
    }


}
